<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * 观察者模式和发布订阅模式的区别：
    *
    * 发布订阅模式：
    *   订阅者把自己想订阅的事件注册到调度中心，当该事件触发的时候，发布者发布该事件到调度中心，
    *   由调度中心统一调度订阅者注册都调度中心的处理代码
    *   处理一对多的场景 ajax的网站登录 微信公众号的自动回复
    *
    * */

    class Obsever{
        event = {} //存储事件的容器
        //{"marry":["fnA","fnB"],"baby":["fnB"]} 这是容器存储内容的格式

        //订阅
        subscribe(type,fn){
            if(typeof this.event[type] === "undefined"){ //如果该事件类型等于undefined，说明是初次订阅，则在里面创建一个该事件类型
                this.event[type] = [fn] //"baby":["fnB"]
            }else{ //否则就是该事件类型已经创建了，后面如果还有人订阅相同的事件，直接push进去
                this.event[type].push(fn) //"baby":["fnB","fnC"]
            }
        }

        //发布
        publish(type,args = {}){
            if(!this.event[type]) return //如果该事件五人订阅，就直接退出

            //否则就是该事件被人订阅了
            //{"marry":["fnA","fnB"],"baby":["fnB"]} 这是容器存储内容的格式
            //假如type为marry，则this.event[marry]就是上面对象中的"marry"属性，则其对应的值就是一个数组["fnA","fnB"]，length为2
            for(let index = 0; index < this.event[type].length; index++){
                this.event[type][index].call(this,args) //事件类型 所对应存储的 回调函数 执行
                //this.event[type]属性所对应的属性值是一个数组，数组取值用[index]，这里用call把this指向当前的实例对象
                //数组中["fnA","fnB"]的值"fnA","fnB"，存储的是subscribe的回调函数，所以args参数会传入到回调函数中
            }
        }
    }

    let obsever = new Obsever()

    obsever.subscribe("marry",function (e){ //回调函数用e接收传入的参数args对象
        console.log("A你好！" + e.message)
    })

    obsever.subscribe("marry",function (e){
        console.log("B你好！" + e.message)
    })

    obsever.subscribe("baby",function (e){
        console.log("B你好！" + e.message)
    })

    obsever.subscribe("baby",function (e){
        console.log("C你好！" + e.message)
    })

    obsever.publish("marry",{message:"我结婚了，一定要来"})
    obsever.publish("baby",{message:"记得包红包"})

</script>
</body>
</html>